package com.alibaba.cloud.clinic.config.mq;

import com.alibaba.cloud.clinic.constant.ClinicConstant;
import com.alibaba.cloud.clinic.constant.ClinicEnum;
import com.alibaba.cloud.clinic.dao.NativeTransactionMessageMapper;
import com.alibaba.cloud.clinic.entity.NativeCorrelationData;
import com.alibaba.cloud.clinic.entity.NativeTransactionMessage;
import com.alibaba.cloud.common.autoconfigure.AliCloudProperties;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Component
public class RabbitMqConfirmCallBack implements RabbitTemplate.ConfirmCallback {

    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMqConfirmCallBack.class);

    @Autowired
    private NativeTransactionMessageMapper nativeMessageMapper;

    @Autowired
    private AliCloudProperties aliCloudProperties;

    private RabbitTemplate rabbitTemplate;

    public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        NativeCorrelationData nativeCorrelationData = null;
        if (correlationData instanceof NativeCorrelationData) {
            nativeCorrelationData = (NativeCorrelationData) correlationData;
        }
        if (nativeCorrelationData == null) {
            return;
        }
        String id = nativeCorrelationData.getId();
        Integer retryNum = nativeCorrelationData.getMaxRetry();
        String exchange = nativeCorrelationData.getExchange();
        String routingKey = nativeCorrelationData.getRoutingKey();
        String messContent = nativeCorrelationData.getMessContent();

        if(ack) {
            String messType = nativeCorrelationData.getMessType();
            if (ClinicEnum.MESSAGE_TYPE.NATIVE_MESS.getValue().equals(messType)) {

                LOGGER.info(ClinicEnum.MESSAGE_TYPE.NATIVE_MESS.name() + " 消息发送成功：{}", nativeCorrelationData.toString());
                // 更新消息表的状态
                UpdateWrapper<NativeTransactionMessage> wrapper = new UpdateWrapper<>();
                wrapper.set("id", id);
                NativeTransactionMessage message = new NativeTransactionMessage();
                message.setStatus(ClinicEnum.MESSAGE_STATUS.SENT.getValue());
                nativeMessageMapper.update(message, wrapper);
            }
            if (ClinicEnum.MESSAGE_TYPE.TRANSMIT_DATA.getValue().equals(messType)) {
                LOGGER.info(ClinicEnum.MESSAGE_TYPE.TRANSMIT_DATA.name() + " 消息发送成功：{}", nativeCorrelationData.toString());
            }
        } else {

            LOGGER.info("消息发送失败：{}, cause:{}", nativeCorrelationData.toString(), cause);
            String mqMaxRetry = aliCloudProperties.getMqMaxRetry();
            if (retryNum < Integer.parseInt(mqMaxRetry)) {
                LOGGER.info("重新投递次数：{}", retryNum);
                AtomicInteger atomicRetry = new AtomicInteger(retryNum);
                nativeCorrelationData.setMaxRetry(atomicRetry.incrementAndGet());
                rabbitTemplate.convertAndSend(exchange, routingKey, messContent, nativeCorrelationData);
                LOGGER.info("重新投递成功：exchange: {}, routingKey: {}, \nmessContent: {}, \nnativeCorrelationData: {}",
                        exchange, routingKey, messContent, nativeCorrelationData);
            } else {
                NativeCorrelationData deadData = new NativeCorrelationData();
                deadData.setId(id);
                deadData.setMaxRetry(retryNum);
                deadData.setMessContent(messContent);
                deadData.setExchange(ClinicConstant.DEAD_LETTER_EXCHANGE);
                deadData.setRoutingKey(ClinicConstant.DEAD_LETTER_ROUTING_KEY);
                deadData.setMessType(ClinicEnum.MESSAGE_TYPE.TRANSMIT_DATA.getValue());
                LOGGER.info("发送消息到死信队列: {}", deadData);
                // 失败3次，发送到死信队列
                rabbitTemplate.convertAndSend(ClinicConstant.DEAD_LETTER_EXCHANGE, ClinicConstant.DEAD_LETTER_ROUTING_KEY, messContent, deadData);
            }
        }
    }
}
